home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / pgp20src.zip / PGP.C < prev    next >
C/C++ Source or Header  |  1992-09-03  |  53KB  |  1,749 lines

  1. #undef TEMP_VERSION    /* if defined, temporary experimental version of PGP */
  2. /*    pgp.c -- main module for PGP.
  3.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  4.  
  5.     Synopsis:  PGP uses public-key encryption to protect E-mail. 
  6.     Communicate securely with people you've never met, with no secure
  7.     channels needed for prior exchange of keys.  PGP is well featured and
  8.     fast, with sophisticated key management, digital signatures, data
  9.     compression, and good ergonomic design.
  10.  
  11.     The original PGP version 1.0 was written by Philip Zimmermann, of
  12.     Phil's Pretty Good(tm) Software.  Many parts of later versions of 
  13.     PGP were developed by an international collaborative effort, 
  14.     involving a number of contributors, including major efforts by:
  15.         Branko Lankester <lankeste@fwi.uva.nl> 
  16.         Hal Finney <74076.1041@compuserve.com>
  17.         Peter Gutmann <pgut1@cs.aukuni.ac.nz>
  18.     Other contributors who ported or translated or otherwise helped include:
  19.         Jean-loup Gailly in France
  20.         Hugh Kennedy in Germany
  21.         Lutz Frank in Germany
  22.         Cor Bosman in The Netherlands
  23.         Felipe Rodriquez Svensson in The Netherlands
  24.         Armando Ramos in Spain
  25.         Miguel Angel Gallardo Ortiz in Spain
  26.         Harry Bush and Maris Gabalins in Latvia
  27.         Zygimantas Cepaitis in Lithuania
  28.         Alexander Smishlajev
  29.         Peter Suchkow and Andrew Chernov in Russia
  30.         David Vincenzetti in Italy
  31.         ...and others.
  32.  
  33.     Note that while many PGP source modules bear the copyright notice of
  34.     Philip Zimmermann, some of them may have been revised or in some
  35.     cases entirely written by other members of the PGP development team,
  36.     who often failed to put their names in their code.
  37.  
  38.     Revisions:
  39.         Version 1.0 - 5 Jun 91
  40.         Version 1.4 - 19 Jan 92
  41.         Version 1.5 - 12 Feb 92
  42.         Version 1.6 - 24 Feb 92
  43.         Version 1.7 - 29 Mar 92
  44.         Version 1.8 - 23 May 92
  45.         Version 2.0 - 2 Sep 92
  46.  
  47.     (c) Copyright 1990-1992 by Philip Zimmermann.  All rights reserved.
  48.     The author assumes no liability for damages resulting from the use
  49.     of this software, even if the damage results from defects in this
  50.     software.  No warranty is expressed or implied.
  51.  
  52.     All the source code Philip Zimmermann wrote for PGP is available for
  53.     free under the "Copyleft" General Public License from the Free
  54.     Software Foundation.  A copy of that license agreement is included in
  55.     the source release package of PGP.  Code developed by others for PGP
  56.     is also freely available.  Other code that has been incorporated into
  57.     PGP from other sources was either originally published in the public
  58.     domain or was used with permission from the various authors.  See the
  59.     PGP User's Guide for more complete information about licensing,
  60.     patent restrictions on certain algorithms, trademarks, copyrights,
  61.     and export controls.  
  62.  
  63.     Philip Zimmermann may be reached at:
  64.         Boulder Software Engineering
  65.         3021 Eleventh Street
  66.         Boulder, Colorado 80304  USA
  67.         (303) 541-0140  (voice or FAX)
  68.         email:  prz@sage.cgd.ucar.edu
  69.  
  70.  
  71.     PGP will run on MSDOS, Sun Unix, VAX/VMS, Ultrix, Atari ST, 
  72.     Commodore Amiga, and OS/2.  Note:  Don't try to do anything with 
  73.     this source code without looking at the PGP User's Guide.
  74.  
  75.     PGP combines the convenience of the Rivest-Shamir-Adleman (RSA)
  76.     public key cryptosystem with the speed of fast conventional
  77.     cryptographic algorithms, fast message digest algorithms, data
  78.     compression, and sophisticated key management.  And PGP performs 
  79.     the RSA functions faster than most other software implementations.  
  80.     PGP is RSA public key cryptography for the masses.
  81.  
  82.     Uses RSA Data Security, Inc. MD5 Message Digest Algorithm
  83.     as a hash for signatures.  Uses the ZIP algorithm for compression.
  84.     Uses the ETH IPES/IDEA algorithm for conventional encryption.
  85.  
  86.     PGP generally zeroes its used stack and memory areas before exiting.
  87.     This avoids leaving sensitive information in RAM where other users
  88.     could find it later.  The RSA library and keygen routines also
  89.     sanitize their own stack areas.  This stack sanitizing has not been
  90.     checked out under all the error exit conditions, when routines exit
  91.     abnormally.  Also, we must find a way to clear the C I/O library
  92.     file buffers, the disk buffers, and and cache buffers.
  93.  
  94.     If you modify this code, PLEASE preserve the style of indentation
  95.     used for {begin...end} blocks.  It drives me bats to have to deal
  96.     with more than one style in the same program.
  97.  
  98. */
  99.  
  100.  
  101. #include <ctype.h>
  102. #ifndef AMIGA
  103. #include <signal.h>
  104. #endif
  105. #include <stdio.h>
  106. #include <stdlib.h>
  107. #include <string.h>
  108. #include "mpilib.h"
  109. #include "random.h"
  110. #include "crypto.h"
  111. #include "fileio.h"
  112. #include "keymgmt.h"
  113. #include "language.h"
  114. #include "pgp.h"
  115. int maintenance(char *ringfile, int options);    /* from keymaint.c */
  116. #ifdef  M_XENIX
  117. char *strstr();
  118. long time();
  119. #endif
  120.  
  121. #ifdef MSDOS
  122. #ifdef __ZTC__    /* Extend stack for Zortech C */
  123. unsigned _stack_ = 12*1024;
  124. #endif
  125. #ifdef __TURBOC__
  126. unsigned _stklen = 12*1024;
  127. #endif
  128. #endif
  129. #define    STACK_WIPE    6000
  130.  
  131. /* Global filenames and system-wide file extensions... */
  132. char rel_version[] = "2.0";    /* release version */
  133. char rel_date[] = "2 Sep 92";    /* release date */
  134. char CTX_EXTENSION[] = ".pgp";
  135. char PGP_EXTENSION[] = ".pgp";
  136. char ASC_EXTENSION[] = ".asc";
  137. char SIG_EXTENSION[] = ".sig";
  138. char BAK_EXTENSION[] = ".bak";
  139. char HLP_EXTENSION[] = ".hlp";
  140. char SCRATCH_KEYRING_FILENAME[] = "_tmpring.pgp"; /* gets modified */
  141. char CONSOLE_FILENAME[] = "_CONSOLE";
  142. char HELP_FILENAME[] = "pgp.hlp";
  143. char SCRATCH_KEYRING_PATH[MAX_PATH];
  144.  
  145. /* These files use the environmental variable PGPPATH as a default path: */
  146. char CONFIG_FILENAME[] = "config.txt";
  147. char PUBLIC_KEYRING_FILENAME[32] = "pubring.pgp";
  148. char SECRET_KEYRING_FILENAME[32] = "secring.pgp";
  149. char RANDSEED_FILENAME[32] = "randseed.bin";
  150.  
  151. /* Flags which are global across the driver code files */
  152. boolean verbose = FALSE;    /* -l option: display maximum information */
  153. FILE    *pgpout;            /* Place for routine messages */
  154.  
  155. /* Prototype for function in config.c */
  156.   
  157. int processConfigFile( const char *configFileName );
  158.  
  159. static void usage();
  160. static void key_usage();
  161. static void arg_error();
  162. static void initsigs();
  163. static void do_keyopt(char);
  164. static void do_decrypt(char *);
  165. static void do_armorfile(char *);
  166. void user_error();
  167. void exitPGP(int);
  168.  
  169.  
  170. boolean strcontains( char *s1, char *s2 )
  171. {    /*
  172.     **    Searches s1 for s2, without case sensitivity.
  173.     **    Return TRUE if found.
  174.     **
  175.     **    If s2 is an empty string then return TRUE.  This is because,
  176.     **    at least in the world of mathematics, the empty set is contained
  177.     **    in all other sets.  The Microsoft C version 6.0 strstr function
  178.     **    behaves this way but version 5.1 does not, so we need to
  179.     **    explicitly test for the situation. -- ALH 91/2/17
  180.     */
  181.  
  182.     if (s2 != NULL && s2[0] != '\0')
  183.     {
  184.         char buf1[256], buf2[256];    /* scratch buffers */
  185.  
  186.         if (s1 != NULL)
  187.         {
  188.             strncpy( buf1, s1, 256 );
  189.             strlwr( buf1 ); /* converts to lower case */
  190.         }
  191.         else
  192.             buf1[0] = '\0';
  193.         strncpy( buf2, s2, 256 );    strlwr( buf2 ); /* converts to lower case */
  194.  
  195.         if (strstr( buf1, buf2 ) == NULL)
  196.             return( FALSE );        /* string not found */
  197.     }
  198.     return(TRUE);
  199. }    /*    strcontains */
  200.  
  201.  
  202. /*    Various compression signatures: PKZIP, Zoo, GIF, Arj, and HPACK.  
  203.     Lha(rc) is handled specially in the code; it is missing from the 
  204.     compressSig structure intentionally.  If more formats are added, 
  205.     put them before lharc to keep the code consistent. 
  206. */
  207. char *compressSig[] =  { "PK\03\04", "ZOO ", "GIF8", "\352\140", "HPAK" };
  208. char *compressName[] = { "PKZIP",   "Zoo",  "GIF",  "Arj",  "Hpack", "LHarc" };
  209. char *compressExt[] =  { ".zip",  ".zoo",  ".gif",  ".arj", ".hpk",  ".lzh" };
  210.  
  211. int compressSignature(byte *header)
  212. /* Returns file signature type from a number of popular compression formats
  213.    or -1 if no match */
  214. {    int i;
  215.  
  216.     for (i=0; i<sizeof(compressSig)/sizeof(*compressSig); i++)
  217.         if (!strncmp((char *)header, compressSig[i], strlen(compressSig[i])))
  218.             return(i);
  219.     /* Special check for lharc files */
  220.     if (header[2]=='-' && header[3]=='l' && (header[4]=='z'||header[4]=='h') &&
  221.         header[6]=='-')
  222.         return(i);
  223.     return(-1);
  224. }    /* compressSignature */
  225.  
  226.  
  227. boolean file_compressible(char *filename)
  228. {    /* returns TRUE iff file is likely to be compressible */
  229.     byte header[8];
  230.     get_header_info_from_file( filename, header, 8 );
  231.     if (compressSignature( header ) >= 0)
  232.         return (FALSE);    /* probably not compressible */
  233.     return (TRUE);    /* possibly compressible */
  234. }    /* compressible */
  235.  
  236.  
  237. /* Possible error exit codes - not all of these are used.  Note that we
  238.    don't use the ANSI EXIT_SUCCESS and EXIT_FAILURE.  To make things
  239.    easier for compilers which don't support enum we use #defines */
  240.  
  241. #define EXIT_OK                    0
  242. #define INVALID_FILE_ERROR        1
  243. #define FILE_NOT_FOUND_ERROR    2
  244. #define UNKNOWN_FILE_ERROR        3
  245. #define NO_BATCH                4
  246. #define BAD_ARG_ERROR            5
  247. #define INTERRUPT                6
  248. #define OUT_OF_MEM                7
  249.  
  250. /* Keyring errors: Base value = 10 */
  251. #define KEYGEN_ERROR            10
  252. #define NONEXIST_KEY_ERROR        11
  253. #define KEYRING_ADD_ERROR        12
  254. #define KEYRING_EXTRACT_ERROR    13
  255. #define KEYRING_EDIT_ERROR        14
  256. #define KEYRING_VIEW_ERROR        15
  257. #define KEYRING_REMOVE_ERROR    16
  258. #define KEYRING_CHECK_ERROR        17
  259. #define KEY_SIGNATURE_ERROR        18
  260. #define KEYSIG_REMOVE_ERROR        19
  261.  
  262. /* Encode errors: Base value = 20 */
  263. #define SIGNATURE_ERROR            20
  264. #define RSA_ENCR_ERROR            21
  265. #define ENCR_ERROR                22
  266. #define COMPRESS_ERROR            23
  267.  
  268. /* Decode errors: Base value = 30 */
  269. #define SIGNATURE_CHECK_ERROR    30
  270. #define RSA_DECR_ERROR            31
  271. #define DECR_ERROR                32
  272. #define DECOMPRESS_ERROR        33
  273.  
  274.  
  275. #ifdef SIGINT
  276. void breakHandler(int sig)
  277. /* This function is called if a BREAK signal is sent to the program.  In this
  278.    case we zap the temporary files.
  279. */
  280. {
  281. #ifdef UNIX
  282.     if (sig != SIGINT)
  283.         fprintf(stderr, "\nreceived signal %d\n", sig);
  284.     else
  285. #endif
  286.         fprintf(pgpout,PSTR("\nStopped at user request\n"));
  287.     exitPGP(INTERRUPT);
  288. }
  289. #endif
  290.  
  291.  
  292. void clearscreen(void)
  293. {    /* Clears screen and homes the cursor. */
  294.     fprintf(pgpout,"\n\033[0;0H\033[J");    /* ANSI sequence. */
  295. }
  296.  
  297.  
  298. #ifdef TEMP_VERSION    /* temporary experimental version of PGP */
  299. #include <time.h>
  300. #define CREATION_DATE ((unsigned long) 0x2a6f17dcL)     
  301.     /* CREATION_DATE is Thu Jul 23 14:34:36 1992 */ 
  302. #define LIFESPAN    ((unsigned long) 30L * (unsigned long) 86400L)
  303.     /* LIFESPAN is 30 days */
  304. void check_expiration_date(void)
  305. {    /* If this is an experimental version of PGP, cut its life short */
  306.     word32 t;
  307.     t = time(NULL);
  308.     if (t > (CREATION_DATE + LIFESPAN))
  309.     {    fprintf(stderr,"\n\007This experimental version of PGP has expired.\n");
  310.         exit(-1);    /* error exit */
  311.     }
  312. }    /* check_expiration_date */
  313. #else    /* no expiration date */
  314. #define check_expiration_date() /* null statement */
  315. #endif    /* TEMP_VERSION */
  316.  
  317.  
  318.  
  319. /* -f means act as a unix-style filter */
  320. /* -l means show longer more descriptive diagnostic messages */
  321. /* -m means display plaintext output on screen, like unix "more" */
  322. /* -d means decrypt only, leaving inner signature wrapping intact */
  323. /* -t means treat as pure text and convert to canonical text format */
  324.  
  325. /* Used by getopt function... */
  326. #define OPTIONS "abcdefghklmo:prstu:vwxABCDEFGHKLMO:PRSTU:VWX?"
  327. extern int optind;
  328. extern char *optarg;
  329.  
  330. boolean emit_radix_64 = FALSE;        /* set by config file */
  331. boolean sign_flag = FALSE;
  332. boolean moreflag = FALSE;
  333. boolean filter_mode = FALSE;
  334. boolean explicit_plainfile = TRUE;
  335. boolean decrypt_only_flag = FALSE;
  336. boolean de_armor_only = FALSE;
  337. boolean strip_sig_flag = FALSE;
  338. boolean maint_check = FALSE;
  339. char lit_mode = MODE_BINARY;    /* MODE_TEXT or MODE_BINARY for literal packet */
  340. /* my_name is substring of default userid for secret key to make signatures */
  341. char my_name[256] = "\0"; /* null my_name means take first userid in ring */
  342. char tmpdir[256];    /* directory for temp files, usually RAMdisk */
  343. char outdir[256];    /* output directory */
  344. char basename[64] = "pgptemp";    /* basename of output file(s) */
  345. boolean keepctx = FALSE;    /* TRUE means keep .ctx file on decrypt */
  346. boolean compress_enabled = TRUE;    /* attempt compression before encryption */
  347. long timeshift = 0L;    /* seconds from GMT timezone */
  348. boolean attempt_compression; /* attempt compression before encryption */
  349. char *outputfile = NULL;
  350. int errorLvl = EXIT_OK;
  351. char mcguffin[256]; /* userid search tag */
  352. char plainfile[MAX_PATH];
  353. #define    MAXARGC    8
  354. int myArgc = 2;
  355. char *myArgv[MAXARGC] = { NULL, };
  356.  
  357. void main(int argc, char *argv[])
  358. {
  359.     int status, opt;
  360.     char *inputfile = NULL;
  361.      char *recipient = NULL;
  362.     char *workfile, *tempf;
  363.     boolean nestflag = FALSE;
  364.     boolean decrypt_mode = FALSE;
  365.     boolean wipeflag = FALSE;
  366.     boolean armor_flag = FALSE;        /* -a option */
  367.     boolean preserve_flag = TRUE;
  368.     boolean separate_signature = FALSE;
  369.     boolean keyflag = FALSE;
  370.     boolean encrypt_flag = FALSE;
  371.     boolean conventional_flag = FALSE;
  372.     char *literal_file = NULL;
  373.     char literal_file_name[MAX_PATH];
  374.     char cipherfile[MAX_PATH];
  375.     char keychar = '\0';
  376.     char *p;
  377.     byte ctb;
  378.  
  379.     /* Initial messages to stderr */
  380.     pgpout = stderr;
  381.  
  382. #ifdef    DEBUG1
  383.     verbose = TRUE;
  384. #endif
  385.  
  386.     /* Process the config file first.  Any command-line arguments will
  387.        override the config file settings */
  388.     buildfilename( mcguffin, CONFIG_FILENAME );
  389.     if ( processConfigFile( mcguffin ) < 0 )
  390.     {    errorLvl = BAD_ARG_ERROR;
  391.         user_error();
  392.     }
  393.     init_charset();
  394.  
  395.     /*    We had to process the config file first to possibly select the 
  396.         foreign language to translate the sign-on line that follows... */
  397.     fprintf(stderr,PSTR("Pretty Good Privacy %s - Public-key encryption for the masses.\n"),
  398.         rel_version);
  399. #ifdef TEMP_VERSION
  400.     fprintf(stderr, "Internal development version only - not for general release.\n");
  401. #endif
  402.     fprintf(stderr, PSTR("(c) 1990-1992 Philip Zimmermann, Phil's Pretty Good Software. %s\n"),
  403.         rel_date);
  404.  
  405.     {    word32 tstamp;
  406.         get_timestamp((byte *)&tstamp);    /* timestamp points to tstamp */
  407.         fprintf(pgpout,"Date: %s\n",ctdate(&tstamp));
  408.     }
  409.  
  410. #ifdef MSDOS    /* only on MSDOS systems */
  411.     if ((p = getenv("TZ")) == NULL || *p == '\0')
  412.     {    fprintf(pgpout,PSTR(
  413. "\007WARNING: Environmental variable TZ is not defined, so GMT timestamps\n\
  414. may be wrong.  See the PGP User's Guide to properly define TZ\n\
  415. in AUTOEXEC.BAT file.\n"));
  416.     }
  417. #endif    /* MSDOS */
  418.  
  419.     if ((p = getenv("TMP")) != NULL && *p != '\0')
  420.         strcpy(tmpdir, p);
  421.  
  422.     if (tmpdir[0] != 0)
  423.     {    p = tmpdir + strlen(tmpdir)-1;
  424.         if (*p != '/' && *p != '\\')
  425.         {    if ((p = strchr(tmpdir, '/')) == NULL &&
  426.                 (p = strchr(tmpdir, '\\')) == NULL)
  427.                 p = "/";
  428.             strncat(tmpdir, p, 1);
  429.         }
  430.     }
  431.         
  432.       /* Process all the command-line option switches: */
  433.      while (optind < argc)
  434.      {    /*
  435.           * Allow random order of options and arguments (like GNU getopt)
  436.           * NOTE: this does not work with GNU getopt, use getopt.c from
  437.           * the PGP distribution.
  438.           */
  439.          if ((opt = getopt(argc, argv, OPTIONS)) == EOF)
  440.          {    if (optind == argc)        /* -- at end */
  441.                  break;
  442.              if (myArgc == MAXARGC)
  443.              {    fprintf(pgpout, PSTR("\007Too many arguments.\n"));
  444.                  errorLvl = BAD_ARG_ERROR;
  445.                  user_error();
  446.              }
  447.              myArgv[myArgc++] = argv[optind++];
  448.              continue;
  449.          }
  450.         opt = tolower(opt);
  451.         if (keyflag && (keychar == '\0' || (keychar == 'v' && opt == 'v')))
  452.         {
  453.             if (keychar == 'v')
  454.                 keychar = 'V';
  455.             else
  456.                 keychar = opt;
  457.             continue;
  458.         }
  459.         switch (opt)
  460.         {
  461.             case 'a': armor_flag = TRUE; emit_radix_64 ^= 1; break;
  462.             case 'b': separate_signature = strip_sig_flag = TRUE; break;
  463.             case 'c': encrypt_flag = conventional_flag = TRUE;
  464.                       maint_check = TRUE; break;
  465.             case 'd': decrypt_only_flag = TRUE; break;
  466.             case 'e': encrypt_flag = TRUE; break;
  467.             case 'f': filter_mode = TRUE; break;
  468.             case '?':
  469.             case 'h': usage(); break;
  470.             case 'k': keyflag = TRUE; break;
  471.             case 'l': verbose = TRUE; break;
  472.             case 'm': moreflag = TRUE; break;
  473.             case 'p': explicit_plainfile = FALSE; break;
  474.             case 'o': outputfile = optarg; break;
  475.             case 's': sign_flag = TRUE; break;
  476.             case 't': lit_mode = (lit_mode == MODE_TEXT ?
  477.                         MODE_BINARY : MODE_TEXT); break;
  478.             case 'u': strncpy(my_name, optarg, sizeof(my_name)-1);
  479.                   INTERNAL(my_name);
  480.                   break;
  481.             case 'w': wipeflag = TRUE; break;
  482.             default:
  483.                 arg_error();
  484.         }
  485.     }
  486.     if (keyflag && keychar == '\0')
  487.         key_usage();
  488.  
  489.     check_expiration_date();    /* hobble any experimental version */
  490.  
  491. #ifndef UNIX
  492.     if (!filter_mode)
  493.         pgpout = stdout;
  494. #endif
  495.  
  496. #ifdef UNIX
  497.     umask(077); /* Make files default to private */
  498. #endif
  499.  
  500.     initsigs();
  501.  
  502.     if (keyflag)
  503.     {    do_keyopt(keychar);
  504.         exitPGP(EXIT_OK);
  505.     }
  506.  
  507.     /* -db means break off signature certificate into separate file */
  508.     if (decrypt_only_flag && strip_sig_flag)
  509.         decrypt_only_flag = FALSE;
  510.  
  511.     if (decrypt_only_flag && armor_flag)
  512.         decrypt_mode = de_armor_only = TRUE;
  513.  
  514.     if (outputfile != NULL)
  515.         explicit_plainfile = TRUE;
  516.  
  517.     if (!sign_flag && !encrypt_flag && !conventional_flag && !armor_flag)
  518.         decrypt_mode = TRUE;
  519.  
  520.      if (myArgc == 2)        /* no arguments */
  521.     {
  522. #ifdef UNIX        /* no need to specify -f when redirecting stdin */
  523.         if (!isatty(fileno(stdin)))
  524.             filter_mode = TRUE;
  525. #endif
  526.         if (!filter_mode)
  527.         {    fprintf(pgpout,PSTR("\nFor details on licensing and distribution, see the PGP User's Guide.\
  528. \nFor other cryptography products and custom development services, contact:\
  529. \nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, phone (303)541-0140\n"));
  530.             if (strcmp((p = PSTR("@translator@")), "@translator@"))
  531.                 fprintf(pgpout, p);
  532.             fprintf(pgpout,PSTR("\nFor a usage summary, type:  pgp -h\n"));
  533.             exit(BAD_ARG_ERROR);        /* error exit */
  534.         }
  535.     }
  536.     else
  537.      {    if (filter_mode)
  538.              recipient = myArgv[2];
  539.          else
  540.          {    inputfile = myArgv[2];
  541.              recipient = myArgv[3];
  542.          }
  543.      }
  544.  
  545.  
  546.     if (filter_mode)
  547.     {    inputfile = "stdin";
  548.         filter_mode = TRUE;
  549.     }
  550.     else
  551.     {    if (decrypt_mode && no_extension(inputfile))
  552.         {    strcpy(cipherfile, inputfile);
  553.             force_extension( cipherfile, ASC_EXTENSION );
  554.             if (file_exists (cipherfile))
  555.                 inputfile = cipherfile;
  556.             else
  557.             {    force_extension( cipherfile, CTX_EXTENSION );
  558.                 if (file_exists (cipherfile))
  559.                     inputfile = cipherfile;
  560.                 else
  561.                 {    force_extension( cipherfile, SIG_EXTENSION );
  562.                     if (file_exists (cipherfile))
  563.                         inputfile = cipherfile;
  564.                 }
  565.             }
  566.         }
  567.         if (! file_exists( inputfile ))
  568.         {    fprintf(pgpout, PSTR("\007File [%s] does not exist.\n"), inputfile);
  569.             errorLvl = FILE_NOT_FOUND_ERROR;
  570.             user_error();
  571.         }
  572.         workfile = inputfile;
  573.     }
  574.  
  575.     if (strlen(inputfile) >= (unsigned) MAX_PATH-4)
  576.     {    fprintf(pgpout, PSTR("\007Invalid filename: [%s] too long\n"), inputfile );
  577.         errorLvl = INVALID_FILE_ERROR;
  578.         user_error();
  579.     }
  580.     strcpy(plainfile, inputfile);
  581.  
  582.     if (outputfile)
  583.         strcpy(outdir, outputfile);
  584.     else
  585.         strcpy(outdir, inputfile);
  586.     strcpy(basename, file_tail(outdir));
  587.     outdir[strlen(outdir) - strlen(basename)] = '\0';
  588.     force_extension(basename, "");
  589. #if !defined(LONGFILENAMES) && !defined(BSD43) && !defined(sun)
  590.     basename[10] = '\0';    /* 14 char limit */
  591. #endif
  592.  
  593.     if (tmpdir[0] == '\0')
  594.         strcpy(tmpdir, outdir);
  595.  
  596.     if (filter_mode)
  597.     {    workfile = tempfile(TMP_WIPE|TMP_TMPDIR);
  598.         readPhantomInput(workfile);
  599.     }
  600.  
  601.     get_header_info_from_file( workfile, &ctb, 1 );
  602.     if (decrypt_mode)
  603.     {    if (!outputfile)
  604.             outputfile = myArgv[3];
  605.         if (!is_ctb(ctb) && is_armor_file(workfile))
  606.             do_armorfile(workfile);
  607.         else
  608.             do_decrypt(workfile);
  609.         exitPGP(EXIT_OK);
  610.     }
  611.  
  612.  
  613.     nestflag = FALSE;    /* assume we will encapsulate in literal packet */
  614.     /* See if plaintext input file was actually created by PGP earlier-- */
  615.     if (!filter_mode && legal_ctb(ctb))
  616.     {    /*    Special case--may be a PGP-created packet, so
  617.             do we inhibit encapsulation in literal packet? */
  618.         fprintf(pgpout, PSTR("\n\007Input file '%s' looks like it may have been created by PGP. "),
  619.             inputfile );
  620.         fprintf(pgpout, PSTR("\nIs it safe to assume that it was created by PGP (y/N)? "));
  621.         if (getyesno('n'))
  622.             nestflag = TRUE;    /* don't re-encapsulate PGP packet */
  623.     }    /* Possible ciphertext input file */
  624.  
  625.     if (preserve_flag || moreflag)
  626.     {    /* Preserve filename across send */
  627.         if (moreflag)        /* special name to cause printout on decrypt */
  628.         {    strcpy (literal_file_name, CONSOLE_FILENAME);
  629.             lit_mode = MODE_TEXT;    /* will check for text file later */
  630.         }
  631.         else
  632.         {    strcpy (literal_file_name, inputfile);
  633. #ifdef MSDOS
  634.             strlwr (literal_file_name);
  635. #endif
  636.         }
  637.         literal_file = literal_file_name;
  638.     }
  639.  
  640.     /*    Make sure non-text files are not accidentally converted 
  641.         to canonical text.  This precaution should only be followed 
  642.         for US ASCII text files, since European text files may have 
  643.         8-bit character codes and still be legitimate text files 
  644.         suitable for conversion to canonical (CR/LF-terminated) 
  645.         text format. */
  646.     if (lit_mode==MODE_TEXT && !is_text_file(workfile))
  647.     {    fprintf(pgpout, 
  648. PSTR("\n\007Warning: '%s' is not a pure text file.\nFile will be treated as binary data.\n"), 
  649.             workfile);
  650.         lit_mode = MODE_BINARY; /* now expect straight binary */
  651.     }
  652.  
  653.     if (moreflag && lit_mode==MODE_BINARY)    /* For eyes only?  Can't display binary file. */
  654.     {    fprintf(pgpout, 
  655.         PSTR("\n\007Error: Only text files may be sent as display-only.\n"));
  656.         errorLvl = INVALID_FILE_ERROR;
  657.         user_error();
  658.     }        
  659.  
  660.  
  661.     /*    See if plainfile looks like it might be incompressible, 
  662.         by examining its contents for compression headers for 
  663.         commonly-used compressed file formats like PKZIP, etc.
  664.         Remember this information for later, when we are deciding
  665.         whether to attempt compression before encryption.
  666.     */
  667.     attempt_compression = compress_enabled && file_compressible(plainfile);
  668.  
  669.  
  670.     if (sign_flag)
  671.     {
  672.         fprintf(pgpout, PSTR("\nA secret key is required to make a signature. "));
  673.         if (my_name[0] == '\0')
  674.         {
  675.             fprintf(pgpout, PSTR("\nYou specified no user ID to select your secret key,\n\
  676. so the default user ID and key will be the most recently\n\
  677. added key on your secret keyring.\n"));
  678.         }
  679.  
  680.         if (lit_mode==MODE_TEXT)
  681.         {        /* Text mode requires becoming canonical */
  682.             tempf = tempfile(TMP_WIPE|TMP_TMPDIR);
  683.             make_canonical( workfile, tempf );
  684.             rmtemp(workfile);
  685.             workfile = tempf;
  686.         }
  687.         if ((emit_radix_64 || encrypt_flag) && !separate_signature)
  688.             tempf = tempfile(TMP_WIPE|TMP_TMPDIR);
  689.         else
  690.             tempf = tempfile(TMP_WIPE);
  691.         status = signfile( nestflag, separate_signature, my_name,
  692.                             workfile, tempf, lit_mode, literal_file );
  693.         rmtemp(workfile);
  694.         workfile = tempf;
  695.  
  696.         if (status < 0) /* signfile failed */
  697.         {    fprintf(pgpout, PSTR("\007Signature error\n") );
  698.             errorLvl = SIGNATURE_ERROR;
  699.             user_error();
  700.         }
  701.  
  702.         /*    If we just sign it without encryption, and we want radix-64
  703.             output, we may as well compress it before converting to 
  704.             radix-64 format. */
  705.         if (attempt_compression && emit_radix_64 && !encrypt_flag)
  706.         {    tempf = tempfile(TMP_WIPE|TMP_TMPDIR);
  707.             squish_file(workfile, tempf);
  708.             rmtemp(workfile);
  709.             workfile = tempf;
  710.         }
  711.  
  712.     }    /* sign file */
  713.     else if (!nestflag)
  714.     {    /*    Prepend CTB_LITERAL byte to plaintext file.
  715.             --sure wish this pass could be optimized away. */
  716.         tempf = tempfile(TMP_WIPE);
  717.         status = make_literal( workfile, tempf, lit_mode, literal_file );
  718.         rmtemp(workfile);
  719.         workfile = tempf;
  720.     }
  721.  
  722.     if (encrypt_flag)
  723.     {
  724.         if (!conventional_flag)
  725.         {
  726.             fprintf(pgpout, PSTR("\n\nRecipient's public key will be used to encrypt. "));
  727.              if (recipient == NULL)
  728.             {    /* no recipient specified on command line */
  729.                 fprintf(pgpout, PSTR("\nA user ID is required to select the recipient's public key. "));
  730.                 fprintf(pgpout, PSTR("\nEnter the recipient's user ID: "));
  731.                 getstring( mcguffin, 255, TRUE );    /* echo keyboard */
  732.             }
  733.             else
  734.             {    /* recipient specified on command line */
  735.                  strcpy( mcguffin, recipient );        /* Userid of recipient */
  736.             }
  737.             INTERNAL(mcguffin);
  738.         }
  739.  
  740.         tempf = tempfile(TMP_WIPE);
  741.         if (conventional_flag)
  742.             status = idea_encryptfile( workfile, tempf, attempt_compression);
  743.         else
  744.             status = encryptfile( mcguffin, workfile, tempf, attempt_compression);
  745.  
  746.         rmtemp(workfile);
  747.         workfile = tempf;
  748.  
  749.         if (status < 0)
  750.         {    fprintf(pgpout, PSTR("\007Encryption error\n") );
  751.             errorLvl = (conventional_flag ? ENCR_ERROR : RSA_ENCR_ERROR);
  752.             user_error();
  753.         }
  754.     }    /* encrypt file */
  755.  
  756.     if (outputfile)        /* explicit output file overrides filter mode */
  757.         filter_mode = (strcmp(outputfile, "-") == 0);
  758.  
  759.     if (filter_mode)
  760.     {    if (emit_radix_64)
  761.         {    tempf = tempfile(TMP_WIPE);
  762.             if (armor_file(workfile, tempf, inputfile) != 0)
  763.             {    errorLvl = UNKNOWN_FILE_ERROR;
  764.                 user_error();
  765.             }
  766.             rmtemp(workfile);
  767.             workfile = tempf;
  768.         }
  769.         writePhantomOutput(workfile);
  770.         rmtemp(workfile);
  771.     }
  772.     else
  773.     {    char name[MAX_PATH];
  774.         if (outputfile)
  775.             strcpy(name, outputfile);
  776.         else
  777.         {    strcpy(name, inputfile);
  778.             force_extension(name, "");
  779.         }
  780.         if (no_extension(name))
  781.         {    if (emit_radix_64)
  782.                 force_extension(name, ASC_EXTENSION);
  783.             else if (sign_flag && separate_signature)
  784.                 force_extension(name, SIG_EXTENSION);
  785.             else
  786.                 force_extension(name, CTX_EXTENSION);
  787.         }
  788.         if (emit_radix_64)
  789.         {    if (armor_file(workfile, name, inputfile) != 0)
  790.             {    errorLvl = UNKNOWN_FILE_ERROR;
  791.                 user_error();
  792.             }
  793.         }
  794.         else
  795.         {    if ((outputfile = savetemp(workfile, name)) == NULL)
  796.             {    errorLvl = UNKNOWN_FILE_ERROR;
  797.                 user_error();
  798.             }
  799.             if (!verbose && encrypt_flag)
  800.                 fprintf(pgpout, PSTR("\nCiphertext file: %s\n"), outputfile);
  801.             else if (!verbose && sign_flag)
  802.                 fprintf(pgpout, PSTR("\nSignature file: %s\n"), outputfile);
  803.         }
  804.     }
  805.  
  806.     if (wipeflag)
  807.     {    /* destroy every trace of plaintext */
  808.         if (wipefile(inputfile) == 0)
  809.         {    remove(inputfile);
  810.             fprintf(pgpout,PSTR("\nFile %s wiped and deleted. "),inputfile);
  811.         }
  812.     }
  813.  
  814.     exitPGP(EXIT_OK);
  815. }    /* main */
  816.  
  817. #ifdef MSDOS
  818. #include <dos.h>
  819. static char *dos_errlst[] = {
  820.     "Write protect error",        /* PSTR ("Write protect error") */
  821.     "Unknown unit",
  822.     "Drive not ready",            /* PSTR ("Drive not ready") */
  823.     "3", "4", "5", "6", "7", "8", "9",
  824.     "Write error",                /* PSTR ("Write error") */
  825.     "Read error",                /* PSTR ("Read error") */
  826.     "General failure",
  827. };
  828.  
  829. /* handler for msdos 'harderrors' */
  830. #ifdef __TURBOC__    /* Turbo C 2.0 */
  831. static int dostrap(int errval)
  832. #else
  833. static int dostrap(unsigned deverr, unsigned errval)
  834. #endif
  835. {
  836.     char errbuf[64];
  837.     int i;
  838.     sprintf(errbuf, "\r\nDOS error: %s\r\n", dos_errlst[errval]);
  839.     i = 0;
  840.     do
  841.         bdos(2,(unsigned int)errbuf[i],0);
  842.     while (errbuf[++i]);
  843.     return(0);    /* ignore (fopen will return NULL) */
  844. }
  845. #endif /* MSDOS */
  846.  
  847. static void initsigs()
  848. {
  849. #ifdef MSDOS
  850. #ifdef __TURBOC__
  851.     harderr(dostrap);
  852. #else /* MSC */
  853.     _harderr(dostrap);
  854. #endif
  855. #endif /* MSDOS */
  856. #ifdef SIGINT
  857. #ifdef ATARI
  858.     signal(SIGINT,(sigfunc_t) breakHandler);
  859. #else
  860.     signal(SIGINT,breakHandler);
  861. #ifdef UNIX
  862.     signal(SIGHUP,breakHandler);
  863.     signal(SIGQUIT,breakHandler);
  864.     signal(SIGPIPE,breakHandler);
  865.     signal(SIGTERM,breakHandler);
  866. #ifndef DEBUG
  867.     signal(SIGSEGV,breakHandler);
  868.     signal(SIGILL,breakHandler);
  869. #ifdef SIGBUS
  870.     signal(SIGBUS,breakHandler);
  871. #endif
  872. #endif /* DEBUG */
  873. #endif /* UNIX */
  874. #endif /* not Atari */
  875. #endif /* SIGINT */
  876. }    /* initsigs */
  877.  
  878.  
  879. static void do_armorfile(char *armorfile)
  880. {
  881.     char *tempf;
  882.     char cipherfile[MAX_PATH];
  883.     boolean changed_name;
  884.     int status;
  885.  
  886.     while (TRUE)
  887.     {    /* Handle transport armor stripping */
  888.         tempf = tempfile(0);
  889.         status = de_armor_file(armorfile,tempf,&changed_name);
  890.         if (status)
  891.         {    fprintf(pgpout,PSTR("\n\007Error: Transport armor stripping failed for file %s\n"),armorfile);
  892.             errorLvl = INVALID_FILE_ERROR;
  893.             user_error();     /* Bad file */
  894.         }
  895.         if (keepctx || de_armor_only)
  896.         {    strcpy(cipherfile, armorfile);
  897.             force_extension(cipherfile, CTX_EXTENSION);
  898.             if ((tempf = savetemp(tempf, cipherfile)) == NULL)
  899.             {    errorLvl = UNKNOWN_FILE_ERROR;
  900.                 user_error();
  901.             }
  902.             fprintf(pgpout,PSTR("Stripped transport armor from '%s', producing '%s'.\n"),
  903.                 armorfile, tempf);
  904.             if (!de_armor_only)
  905.                 do_decrypt(tempf);
  906.         }
  907.         else
  908.         {    do_decrypt(tempf);
  909.             rmtemp(tempf);
  910.         }
  911.  
  912.         if (!is_armor_file(armorfile))
  913.             break;
  914.  
  915.         fprintf (pgpout, PSTR("\nLooking for next packet in '%s'...\n"), armorfile);
  916.     }
  917. }    /* do_armorfile */
  918.  
  919.  
  920. static void do_decrypt(char *cipherfile)
  921. {
  922.     char *outfile = NULL;
  923.     int status, i;
  924.     boolean nested_info = FALSE;
  925.     char ringfile[MAX_PATH];
  926.     byte ctb;
  927.     byte header[8]; /* used to classify file type at the end. */
  928.  
  929. #ifdef UNIX    /* don't write output to tty: use preserved filename */
  930.     if (filter_mode && !moreflag && isatty(1) && !outputfile)
  931.     {    explicit_plainfile = FALSE;
  932.         filter_mode = FALSE;
  933.     }
  934. #endif
  935.     do    /* while nested parsable info present */
  936.     {
  937.         if (nested_info)
  938.         {    rmtemp(cipherfile);        /* never executed on first pass */
  939.             cipherfile = outfile;
  940.         }
  941.         if (get_header_info_from_file( cipherfile, &ctb, 1) < 0)
  942.         {    fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),cipherfile);
  943.             errorLvl = FILE_NOT_FOUND_ERROR;
  944.             user_error();
  945.         }
  946.  
  947.         if (!is_ctb(ctb))        /* not a real CTB -- complain */
  948.             break;
  949.  
  950.         outfile = tempfile(TMP_WIPE);
  951.  
  952.         /* PKE is Public Key Encryption */
  953.         if (is_ctb_type( ctb, CTB_PKE_TYPE ))
  954.         {
  955.             fprintf(pgpout,PSTR("\nFile is encrypted.  Secret key is required to read it. "));
  956.  
  957.             /* Decrypt to scratch file since we may have a LITERAL2 */
  958.             status = decryptfile( cipherfile, outfile );
  959.  
  960.             if (status < 0) /* error return */
  961.             {    errorLvl = RSA_DECR_ERROR;
  962.                 user_error();
  963.             }
  964.             nested_info = (status > 0);
  965.         }        /* outer CTB is PKE type */
  966.  
  967.         if (is_ctb_type( ctb, CTB_SKE_TYPE ))
  968.         {
  969.             if (decrypt_only_flag)
  970.             {
  971.                 copyfiles_by_name( cipherfile, outfile );
  972.                 fprintf(pgpout,PSTR("\nThis file has a signature, which will be left in place.\n"));
  973.                 break;    /* Do no more */
  974.             }
  975.             fprintf(pgpout,PSTR("\nFile has signature.  Public key is required to check signature. "));
  976.  
  977.             /* check_signaturefile may alter outfile */
  978.             status = check_signaturefile( cipherfile, outfile, strip_sig_flag, explicit_plainfile );
  979.  
  980.             if (status < 0) /* error return */
  981.             {    errorLvl = SIGNATURE_CHECK_ERROR;
  982.                 user_error();
  983.             }
  984.             nested_info = (status > 0);
  985.  
  986.             if (strip_sig_flag || *outfile == '\0')
  987.             {    fprintf(pgpout, "\n");
  988.                 return;
  989.             }
  990.         }        /* outer CTB is SKE type */
  991.  
  992.  
  993.         if (is_ctb_type( ctb, CTB_CKE_TYPE ))
  994.         {        /* Conventional Key Encrypted ciphertext. */
  995.             /* Tell user it's encrypted here, and prompt for password in subroutine. */
  996.             fprintf(pgpout,PSTR("\nFile is conventionally encrypted.  "));
  997.             /* Decrypt to scratch file since it may be a LITERAL2 */
  998.             status = idea_decryptfile( cipherfile, outfile );
  999.             if (status < 0) /* error return */
  1000.             {    errorLvl = DECR_ERROR;
  1001.                 user_error();    /* error exit status */
  1002.             }
  1003.             nested_info = (status > 0);
  1004.         }        /* CTB is CKE type */
  1005.  
  1006.  
  1007.         if (is_ctb_type( ctb, CTB_COMPRESSED_TYPE ))
  1008.         {        /* Compressed text. */
  1009.             status = decompress_file( cipherfile, outfile );
  1010.             if (status < 0) /* error return */
  1011.             {    errorLvl = DECOMPRESS_ERROR;
  1012.                 user_error();
  1013.             }
  1014.             /* Always assume nested information... */
  1015.             nested_info = TRUE;
  1016.         }        /* CTB is COMPRESSED type */
  1017.  
  1018.  
  1019.         if (is_ctb_type( ctb, CTB_LITERAL_TYPE ))
  1020.         {        /* Raw plaintext.  Just copy it.  No more nesting. */
  1021.             /* Strip off CTB_LITERAL prefix byte from file: */
  1022.             /* strip_literal may alter plainfile; will set mode */
  1023.             status = strip_literal( cipherfile, outfile,
  1024.                     explicit_plainfile, &lit_mode);
  1025.             if (status < 0) /* error return */
  1026.             {    errorLvl = UNKNOWN_FILE_ERROR;
  1027.                 user_error();
  1028.             }
  1029.             nested_info = FALSE;
  1030.         }        /* CTB is LITERAL type */
  1031.  
  1032.  
  1033.         if ((ctb == CTB_CERT_SECKEY) || (ctb == CTB_CERT_PUBKEY))
  1034.         {        /* Key ring.  View it. */
  1035.             fprintf(pgpout, PSTR("\nFile contains key(s).  Contents follow...") );
  1036.             if (filter_mode)
  1037.             {    if (view_keyring( NULL, cipherfile, TRUE ) < 0)
  1038.                 {    errorLvl = KEYRING_VIEW_ERROR;
  1039.                     user_error();
  1040.                 }
  1041.                 return; /*    No output file */
  1042.             }
  1043.             if (ctb == CTB_CERT_SECKEY)
  1044.                 buildfilename(ringfile,SECRET_KEYRING_FILENAME);
  1045.             else
  1046.                 buildfilename(ringfile,PUBLIC_KEYRING_FILENAME);
  1047.             /*    Ask if it should be put on key ring */
  1048.             status = addto_keyring(cipherfile,ringfile,TRUE);
  1049.             if (status < 0)
  1050.             {    fprintf(pgpout, PSTR("\007Keyring add error. ") );
  1051.                 errorLvl = KEYRING_ADD_ERROR;
  1052.                 user_error();
  1053.             }
  1054.             if (status == 1)    /* user didn't want to add the keys */
  1055.             {    copyfiles_by_name( cipherfile, outfile );
  1056.                 nested_info = FALSE;
  1057.             }
  1058.             else
  1059.                 return; /*    No output file */
  1060.         }        /* key ring.  view it. */
  1061.  
  1062.     } while (nested_info);
  1063.     /* No more nested parsable information */
  1064.  
  1065.     if (outfile == NULL)    /* file was not encrypted */
  1066.     {    if (!filter_mode && !moreflag)
  1067.         {    fprintf(pgpout,PSTR("\007\nError: '%s' is not a ciphertext, signature, or key file.\n"),
  1068.                 cipherfile);
  1069.             errorLvl = UNKNOWN_FILE_ERROR;
  1070.             user_error();
  1071.         }
  1072.         outfile = cipherfile;
  1073.     }
  1074.     else
  1075.         rmtemp(cipherfile);
  1076.  
  1077.     if (moreflag || (strcmp(outfile,CONSOLE_FILENAME) == 0))
  1078.     {    /* blort to screen */
  1079.         if (strcmp(outfile,CONSOLE_FILENAME) == 0)
  1080.         {    fprintf(pgpout, 
  1081.             PSTR("\n\nThis message is marked \"For your eyes only\".  Display now (Y/n)? "));
  1082.             if (!getyesno('y'))
  1083.             {    /* no -- abort display, and clean up */
  1084.                 wipefile(CONSOLE_FILENAME);
  1085.                 remove(CONSOLE_FILENAME);
  1086.                 return;
  1087.             }
  1088.         }
  1089.         fprintf(pgpout, PSTR("\n\nPlaintext message follows...\n"));
  1090.         more_file(outfile);
  1091.         /* Disallow saving to disk if outfile is console-only: */
  1092.         if (moreflag && strcmp(outfile,CONSOLE_FILENAME) != 0)
  1093.         {    fprintf(pgpout, PSTR("Save this file permanently (y/N)? "));
  1094.             if (getyesno('n'))
  1095.             {    char moreFilename[256];
  1096.                 fprintf(pgpout,PSTR("Enter filename to save file as: "));
  1097.                 getstring( moreFilename, 255, TRUE );
  1098.                 savetemp (outfile, moreFilename);
  1099.                 return;
  1100.             }
  1101.             rmtemp(outfile);
  1102.             return;
  1103.         }
  1104.          if (strcmp(outfile,CONSOLE_FILENAME) == 0)
  1105.         {    /* outfile is console only.  Burn after reading! */
  1106.             wipefile(CONSOLE_FILENAME);
  1107.             remove(CONSOLE_FILENAME);
  1108.             clearscreen();    /* remove all evidence */
  1109.             return;
  1110.         }
  1111.     }    /* blort to screen */
  1112.  
  1113.     if (outputfile)
  1114.     {    if (!strcmp(outfile, "/dev/null"))
  1115.         {    rmtemp(outfile);
  1116.             return;
  1117.         }
  1118.         filter_mode = (strcmp(outputfile, "-") == 0);
  1119.         strcpy(plainfile, outputfile);
  1120.     }
  1121.     else
  1122.         force_extension(plainfile, "");
  1123.  
  1124.     if (filter_mode)
  1125.     {    writePhantomOutput(outfile);
  1126.         rmtemp(outfile);
  1127.         fprintf(pgpout, "\n");
  1128.         return;
  1129.     }
  1130.  
  1131.     if ((outfile = savetemp(outfile, plainfile)) == NULL)
  1132.     {    errorLvl = UNKNOWN_FILE_ERROR;
  1133.         user_error();
  1134.     }
  1135.     if (strcmp(plainfile, outfile) != 0)
  1136.         strcpy(plainfile, outfile);
  1137.  
  1138.     if (!verbose)    /* if other filename messages were suppressed */
  1139.         fprintf(pgpout,PSTR("\nPlaintext filename: %s"), plainfile);
  1140.  
  1141.  
  1142.     /*---------------------------------------------------------*/
  1143.  
  1144.     /*    One last thing-- let's attempt to classify some of the more
  1145.         frequently occurring cases of plaintext output files, as an
  1146.         aid to the user.
  1147.  
  1148.         For example, if output file is a public key, it should have
  1149.         the right extension on the filename.
  1150.  
  1151.         Also, it will likely be common to encrypt files created by
  1152.         various archivers, so they should be renamed with the archiver
  1153.         extension.
  1154.     */
  1155.     get_header_info_from_file( plainfile, header, 8 );
  1156.  
  1157.     if (header[0] == CTB_CERT_PUBKEY)
  1158.     {    /* Special case--may be public key, worth renaming */
  1159.         fprintf(pgpout, PSTR("\nPlaintext file '%s' looks like it contains a public key."),
  1160.             plainfile );
  1161.         maybe_force_extension( plainfile, PGP_EXTENSION );
  1162.     }    /* Possible public key output file */
  1163.  
  1164.     else
  1165.     if ((i = compressSignature( header )) >= 0)
  1166.     {    /*    Special case--may be an archived/compressed file, worth renaming    */
  1167.         fprintf(pgpout, PSTR("\nPlaintext file '%s' looks like a %s file."),
  1168.             plainfile, compressName[i] );
  1169.         maybe_force_extension( plainfile, compressExt[i] );
  1170.     }    /*    Possible archived/compressed output file    */
  1171.  
  1172.     else
  1173.     if (is_ctb(header[0]) &&
  1174.        (is_ctb_type (header[0], CTB_PKE_TYPE)
  1175.      || is_ctb_type (header[0], CTB_SKE_TYPE)
  1176.      || is_ctb_type (header[0], CTB_CKE_TYPE)))
  1177.     {    /* Special case--may be another ciphertext file, worth renaming */
  1178.         fprintf(pgpout, PSTR("\n\007Output file '%s' may contain more ciphertext or signature."),
  1179.             plainfile );
  1180.         maybe_force_extension( plainfile, CTX_EXTENSION );
  1181.     }    /* Possible ciphertext output file */
  1182.  
  1183.     fprintf (pgpout, "\n");
  1184.  
  1185. } /* do_decrypt */
  1186.  
  1187.  
  1188. static void do_keyopt(char keychar)
  1189. {
  1190.     char keyfile[MAX_PATH];
  1191.     char ringfile[MAX_PATH];
  1192.     int status;
  1193.  
  1194.     if (filter_mode)
  1195.     {    errorLvl = NO_BATCH;
  1196.         user_error();     /* interactive process, no go in batch mode */
  1197.     }
  1198.  
  1199.     switch (keychar)
  1200.     {
  1201.  
  1202.         /*-------------------------------------------------------*/
  1203.         case 'g':
  1204.         {    /*    Key generation
  1205.                 Arguments: bitcount, bitcount
  1206.             */
  1207.             char    keybits[6], ebits[6];
  1208.  
  1209.             if (myArgc > 2)
  1210.                 strncpy( keybits, myArgv[2], sizeof(keybits)-1 );
  1211.             else
  1212.                 keybits[0] = '\0';
  1213.  
  1214.             if (myArgc > 3)
  1215.                 strncpy( ebits, myArgv[3], sizeof(ebits)-1 );
  1216.             else
  1217.                 ebits[0] = '\0';
  1218.  
  1219.             /* dokeygen writes the keys out to the key rings... */
  1220.             status = dokeygen(keybits, ebits);
  1221.  
  1222.             if (status < 0)
  1223.             {    fprintf(pgpout, PSTR("\007Keygen error. ") );
  1224.                 errorLvl = KEYGEN_ERROR;
  1225.                 user_error();
  1226.             }
  1227.             return;
  1228.         }    /* Key generation */
  1229.  
  1230.         /*-------------------------------------------------------*/
  1231.         case 'c':
  1232.         {    /*    Key checking
  1233.                 Arguments: userid, ringfile
  1234.             */
  1235.  
  1236.             if (myArgc < 3)        /* Default to all user ID's */
  1237.                 mcguffin[0] = '\0';
  1238.             else
  1239.             {    strcpy ( mcguffin, myArgv[2] );
  1240.                 if (strcmp( mcguffin, "*" ) == 0)
  1241.                     mcguffin[0] = '\0';
  1242.             }
  1243.             INTERNAL(mcguffin);
  1244.  
  1245.             if (myArgc < 4) /* default key ring filename */
  1246.                 buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
  1247.             else
  1248.                 strncpy( ringfile, myArgv[3], sizeof(ringfile)-1 );
  1249.  
  1250.             if ((myArgc < 4 && myArgc > 2)    /* Allow just key file as arg */
  1251.             && has_extension( myArgv[2], PGP_EXTENSION ) )
  1252.             {    strcpy( ringfile, myArgv[2] );
  1253.                 mcguffin[0] = '\0';
  1254.             }
  1255.  
  1256.             status = dokeycheck( mcguffin, ringfile, NULL );
  1257.  
  1258.             errorLvl = 0;
  1259.             if (status < 0)
  1260.             {    fprintf(pgpout, PSTR("\007Keyring check error. ") );
  1261.                 errorLvl = KEYRING_CHECK_ERROR;
  1262.             }
  1263.             if (errorLvl == 0 && mcguffin[0] != '\0')
  1264.                 return;    /* just checking a single user, dont do maintenance */
  1265.  
  1266.             if ((status = maintenance(ringfile, 0)) < 0 && status != -7)
  1267.             {    fprintf(pgpout, PSTR("\007Maintenance pass error. ") );
  1268.                 errorLvl = KEYRING_CHECK_ERROR;
  1269.             }
  1270.             if (errorLvl)
  1271.                 user_error();
  1272.  
  1273.             return;
  1274.         }    /* Key check */
  1275.  
  1276.         /*-------------------------------------------------------*/
  1277.         case 'm':
  1278.         {    /*    Maintenance pass
  1279.                 Arguments: ringfile
  1280.             */
  1281.  
  1282.             if (myArgc < 3) /* default key ring filename */
  1283.                 buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
  1284.             else
  1285.                 strcpy( ringfile, myArgv[2] );
  1286.  
  1287. #ifdef MSDOS
  1288.             strlwr( ringfile );
  1289. #endif
  1290.             if (! file_exists( ringfile ))
  1291.                 default_extension( ringfile, PGP_EXTENSION );
  1292.  
  1293.             if ((status = maintenance(ringfile,
  1294.                     MAINT_VERBOSE|(maint_check ? MAINT_CHECK : 0))) < 0)
  1295.             {    if (status == -7)
  1296.                     fprintf(pgpout, PSTR("File '%s' is not a public keyring\n"), ringfile);
  1297.                 fprintf(pgpout, PSTR("\007Maintenance pass error. ") );
  1298.                 errorLvl = KEYRING_CHECK_ERROR;
  1299.                 user_error();
  1300.             }
  1301.             return;
  1302.         }    /* Maintenance pass */
  1303.  
  1304.         /*-------------------------------------------------------*/
  1305.         case 's':
  1306.         {    /*    Key signing
  1307.                 Arguments: her_id, keyfile
  1308.             */
  1309.  
  1310.             if (myArgc >= 4)
  1311.                 strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 );
  1312.             else
  1313.                 buildfilename( keyfile, PUBLIC_KEYRING_FILENAME );
  1314.  
  1315.             if (myArgc >= 3)
  1316.                 strcpy( mcguffin, myArgv[2] );    /* Userid to sign */
  1317.             else
  1318.             {
  1319.                 fprintf(pgpout, PSTR("\nA user ID is required to select the public key you want to sign. "));
  1320.                 fprintf(pgpout, PSTR("\nEnter the public key's user ID: "));
  1321.                 getstring( mcguffin, 255, TRUE );    /* echo keyboard */
  1322.             }
  1323.             INTERNAL(mcguffin);
  1324.  
  1325.             if (my_name[0] == '\0')
  1326.             {
  1327.                 fprintf(pgpout, PSTR("\nA secret key is required to make a signature. "));
  1328.                 fprintf(pgpout, PSTR("\nYou specified no user ID to select your secret key,\n\
  1329. so the default user ID and key will be the most recently\n\
  1330. added key on your secret keyring.\n"));
  1331.             }
  1332.  
  1333.             status = signkey ( mcguffin, my_name, keyfile );
  1334.  
  1335.             if (status >= 0) {
  1336.                 status = maintenance(keyfile, MAINT_SILENT);
  1337.                 if (status == -7)    /* ringfile is a keyfile or secret keyring */
  1338.                 {    fprintf(pgpout, "Warning: '%s' is not a public keyring\n", keyfile);
  1339.                     return;
  1340.                 }
  1341.                 if (status < 0)
  1342.                     fprintf(pgpout, PSTR("\007Maintenance pass error. ") );
  1343.             }
  1344.  
  1345.             if (status < 0)
  1346.             {    fprintf(pgpout, PSTR("\007Key signature error. ") );
  1347.                 errorLvl = KEY_SIGNATURE_ERROR;
  1348.                 user_error();
  1349.             }
  1350.             return;
  1351.         }    /* Key signing */
  1352.  
  1353.  
  1354.         /*-------------------------------------------------------*/
  1355.         case 'd':
  1356.         {    /*    Key compromise
  1357.                 Arguments: userid, keyfile
  1358.             */
  1359.  
  1360.             if (myArgc >= 4)
  1361.                 strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 );
  1362.             else
  1363.                 buildfilename( keyfile, PUBLIC_KEYRING_FILENAME );
  1364.  
  1365.             if (myArgc >= 3)
  1366.                 strcpy( mcguffin, myArgv[2] );    /* Userid to sign */
  1367.             else
  1368.             {
  1369.                 fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to revoke. "));
  1370.                 fprintf(pgpout, PSTR("\nEnter user ID: "));
  1371.                 getstring( mcguffin, 255, TRUE );    /* echo keyboard */
  1372.             }
  1373.             INTERNAL(mcguffin);
  1374.  
  1375.             status = compromise ( mcguffin, keyfile );
  1376.  
  1377.             if (status >= 0) {
  1378.                 status = maintenance(keyfile, MAINT_SILENT);
  1379.                 if (status == -7)    /* ringfile is a keyfile or secret keyring */
  1380.                 {    fprintf(pgpout, "Warning: '%s' is not a public keyring\n", keyfile);
  1381.                     return;
  1382.                 }
  1383.                 if (status < 0)
  1384.                     fprintf(pgpout, PSTR("\007Maintenance pass error. ") );
  1385.             }
  1386.  
  1387.             if (status < 0)
  1388.             {
  1389.                 errorLvl = KEY_SIGNATURE_ERROR;
  1390.                 user_error();
  1391.             }
  1392.             return;
  1393.         }    /* Key compromise */
  1394.  
  1395.         /*-------------------------------------------------------*/
  1396.         case 'e':
  1397.         {    /*    Key editing
  1398.                 Arguments: userid, ringfile
  1399.             */
  1400.  
  1401.             if (myArgc >= 4)
  1402.                 strncpy( ringfile, myArgv[3], sizeof(ringfile)-1 );
  1403.             else    /* default key ring filename */
  1404.                 buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
  1405.  
  1406.             if (myArgc >= 3)
  1407.                 strcpy( mcguffin, myArgv[2] );    /* Userid to edit */
  1408.             else
  1409.             {
  1410.                 fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to edit. "));
  1411.                 fprintf(pgpout, PSTR("\nEnter the key's user ID: "));
  1412.                 getstring( mcguffin, 255, TRUE );    /* echo keyboard */
  1413.             }
  1414.             INTERNAL(mcguffin);
  1415.  
  1416.             status = dokeyedit( mcguffin, ringfile );
  1417.  
  1418.             if (status >= 0) {
  1419.                 status = maintenance(ringfile, MAINT_SILENT);
  1420.                 if (status < 0 && status != -7)
  1421.                     fprintf(pgpout, PSTR("\007Maintenance pass error. ") );
  1422.             }
  1423.  
  1424.             if (status < 0 && status != -7)
  1425.             {    fprintf(pgpout, PSTR("\007Keyring edit error. ") );
  1426.                 errorLvl = KEYRING_EDIT_ERROR;
  1427.                 user_error();
  1428.             }
  1429.             return;
  1430.         }    /* Key edit */
  1431.  
  1432.         /*-------------------------------------------------------*/
  1433.         case 'a':
  1434.         {    /*    Add key to key ring
  1435.                 Arguments: keyfile, ringfile
  1436.             */
  1437.  
  1438.             if (myArgc < 3)
  1439.                 arg_error();
  1440.  
  1441.             strncpy( keyfile, myArgv[2], sizeof(keyfile)-1 );
  1442.  
  1443. #ifdef MSDOS
  1444.             strlwr( keyfile     );
  1445. #endif
  1446.             if (! file_exists( keyfile ))
  1447.                 default_extension( keyfile, PGP_EXTENSION );
  1448.  
  1449.             if (! file_exists( keyfile ))
  1450.             {    fprintf(pgpout, PSTR("\n\007Key file '%s' does not exist.\n"), keyfile );
  1451.                 errorLvl = NONEXIST_KEY_ERROR;
  1452.                 user_error();
  1453.             }
  1454.  
  1455.             if (myArgc < 4) /* default key ring filename */
  1456.             {    byte ctb;
  1457.                 get_header_info_from_file(keyfile, &ctb, 1);
  1458.                 if (ctb == CTB_CERT_SECKEY)
  1459.                     buildfilename(ringfile,SECRET_KEYRING_FILENAME);
  1460.                 else
  1461.                     buildfilename(ringfile,PUBLIC_KEYRING_FILENAME);
  1462.             }
  1463.             else
  1464.             {    strncpy( ringfile, myArgv[3], sizeof(ringfile)-1 );
  1465.                 default_extension( ringfile, PGP_EXTENSION );
  1466.             }
  1467. #ifdef MSDOS
  1468.             strlwr( ringfile );
  1469. #endif
  1470.  
  1471.             status = addto_keyring( keyfile, ringfile, FALSE );
  1472.  
  1473.             if (status < 0)
  1474.             {    fprintf(pgpout, PSTR("\007Keyring add error. ") );
  1475.                 errorLvl = KEYRING_ADD_ERROR;
  1476.                 user_error();
  1477.             }
  1478.             return;
  1479.         }    /* Add key to key ring */
  1480.  
  1481.         /*-------------------------------------------------------*/
  1482.         case 'x':
  1483.         {    /*    Extract key from key ring
  1484.                 Arguments: mcguffin, keyfile, ringfile
  1485.             */
  1486.  
  1487.             if (myArgc >= 5)    /* default key ring filename */
  1488.                 strncpy( ringfile, myArgv[4], sizeof(ringfile)-1 );
  1489.             else
  1490.                 buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
  1491.  
  1492.             if (myArgc >= 3)
  1493.                 strcpy( mcguffin, myArgv[2] );    /* Userid to extract */
  1494.             else
  1495.             {
  1496.                 fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to extract. "));
  1497.                 fprintf(pgpout, PSTR("\nEnter the key's user ID: "));
  1498.                 getstring( mcguffin, 255, TRUE );    /* echo keyboard */
  1499.             }
  1500.             INTERNAL(mcguffin);
  1501.  
  1502.             if (myArgc >= 4)
  1503.             {    strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 );
  1504.             }
  1505.             else
  1506.                 keyfile[0] = '\0';
  1507.  
  1508. #ifdef MSDOS
  1509.             strlwr( keyfile     );
  1510.             strlwr( ringfile );
  1511. #endif
  1512.  
  1513.             default_extension( ringfile, PGP_EXTENSION );
  1514.  
  1515.             status = extract_from_keyring( mcguffin, keyfile,
  1516.                     ringfile, emit_radix_64 );
  1517.  
  1518.             if (status < 0)
  1519.             {    fprintf(pgpout, PSTR("\007Keyring extract error. ") );
  1520.                 errorLvl = KEYRING_EXTRACT_ERROR;
  1521.                 user_error();
  1522.             }
  1523.             return;
  1524.         }    /* Extract key from key ring */
  1525.  
  1526.         /*-------------------------------------------------------*/
  1527.         case 'r':
  1528.         {    /*    Remove keys or selected key signatures from userid keys
  1529.                 Arguments: userid, ringfile
  1530.             */
  1531.  
  1532.             if (myArgc >= 4)
  1533.                 strcpy( ringfile, myArgv[3] );
  1534.             else    /* default key ring filename */
  1535.                 buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
  1536.  
  1537.             if (myArgc >= 3)
  1538.                 strcpy( mcguffin, myArgv[2] );    /* Userid to work on */
  1539.             else
  1540.             {    if (sign_flag)
  1541.                 {
  1542.                     fprintf(pgpout, PSTR("\nA user ID is required to select the public key you want to\n\
  1543. remove certifying signatures from. "));
  1544.                 }
  1545.                 else
  1546.                 {
  1547.                     fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to remove. "));
  1548.                 }
  1549.                 fprintf(pgpout, PSTR("\nEnter the key's user ID: "));
  1550.                 getstring( mcguffin, 255, TRUE );    /* echo keyboard */
  1551.             }
  1552.             INTERNAL(mcguffin);
  1553.  
  1554. #ifdef MSDOS
  1555.             strlwr( ringfile );
  1556. #endif
  1557.             if (! file_exists( ringfile ))
  1558.                 default_extension( ringfile, PGP_EXTENSION );
  1559.  
  1560.             if (sign_flag)        /* Remove signatures */
  1561.             {    if (remove_sigs( mcguffin, ringfile ) < 0)
  1562.                 {    fprintf(pgpout, PSTR("\007Key signature remove error. ") );
  1563.                     errorLvl = KEYSIG_REMOVE_ERROR;
  1564.                     user_error();
  1565.                 }
  1566.             }
  1567.             else        /* Remove keyring */
  1568.             {    if (remove_from_keyring( NULL, mcguffin, ringfile ) < 0)
  1569.                 {    fprintf(pgpout, PSTR("\007Keyring remove error. ") );
  1570.                     errorLvl = KEYRING_REMOVE_ERROR;
  1571.                     user_error();
  1572.                 }
  1573.             }
  1574.             if ((status = maintenance(ringfile, MAINT_SILENT)) < 0 && status != -7)
  1575.             {    fprintf(pgpout, PSTR("\007Maintenance pass error. ") );
  1576.                 errorLvl = KEYRING_CHECK_ERROR;
  1577.                 user_error();
  1578.             }
  1579.             return;
  1580.         }    /* remove key signatures from userid */
  1581.  
  1582.         /*-------------------------------------------------------*/
  1583.         case 'v':
  1584.         case 'V':        /* -kvv */
  1585.         {    /*    View or remove key ring entries, with userid match
  1586.                 Arguments: userid, ringfile
  1587.             */
  1588.  
  1589.             if (myArgc < 4) /* default key ring filename */
  1590.                 buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
  1591.             else
  1592.                 strcpy( ringfile, myArgv[3] );
  1593.  
  1594.             if (myArgc > 2)
  1595.             {    strcpy( mcguffin, myArgv[2] );
  1596.                 if (strcmp( mcguffin, "*" ) == 0)
  1597.                     mcguffin[0] = '\0';
  1598.             }
  1599.             else
  1600.                 *mcguffin = '\0';
  1601.  
  1602.             if ((myArgc == 3) && has_extension( myArgv[2], PGP_EXTENSION ))
  1603.             {    strcpy( ringfile, myArgv[2] );
  1604.                 mcguffin[0] = '\0';
  1605.             }
  1606.             INTERNAL(mcguffin);
  1607.  
  1608. #ifdef MSDOS
  1609.             strlwr( ringfile );
  1610. #endif
  1611.             if (! file_exists( ringfile ))
  1612.                 default_extension( ringfile, PGP_EXTENSION );
  1613.  
  1614.             if (keychar == 'v' || keychar == 'V')
  1615.                 /* If a second 'v' (keychar = V), show signatures too */
  1616.                 if (view_keyring(mcguffin, ringfile, (keychar == 'V')) < 0)
  1617.                 {    fprintf(pgpout, PSTR("\007Keyring view error. ") );
  1618.                     errorLvl = KEYRING_VIEW_ERROR;
  1619.                     user_error();
  1620.                 }
  1621.             return;
  1622.         }    /* view key ring entries, with userid match */
  1623.  
  1624.  
  1625.         default:
  1626.             arg_error();
  1627.     }
  1628.  
  1629. } /* do_keyopt */
  1630.  
  1631.  
  1632.  
  1633. void user_error() /* comes here if user made a boo-boo. */
  1634. {
  1635.     fprintf(pgpout,PSTR("\nFor a usage summary, type:  pgp -h\n"));
  1636.     fprintf(pgpout,PSTR("For more detailed help, consult the PGP User's Guide.\n"));
  1637.     exitPGP(errorLvl);        /* error exit */
  1638. }
  1639.  
  1640. /*
  1641.  * exitPGP: wipes and removes temporary files, also tries to wipe
  1642.  * the stack.
  1643.  */
  1644. void exitPGP(int returnval)
  1645. {
  1646.     char buf[STACK_WIPE];
  1647.  
  1648.     if (moreflag)
  1649.     {    wipefile(CONSOLE_FILENAME);
  1650.         remove(CONSOLE_FILENAME);
  1651.     }
  1652.     cleanup_tmpf();
  1653.     memset(buf, 0, sizeof(buf));    /* wipe stack */
  1654.     exit(returnval);
  1655. }
  1656.  
  1657.  
  1658. static void arg_error()
  1659. {
  1660.     fprintf(pgpout,PSTR("\nInvalid arguments.\n"));
  1661.     errorLvl = BAD_ARG_ERROR;
  1662.     user_error();
  1663. }
  1664.  
  1665. static void build_helpfile(char *helpfile)
  1666. {
  1667.     if (strcmp(language, "en"))
  1668.     {    buildfilename(helpfile, language);
  1669.         force_extension(helpfile, HLP_EXTENSION);
  1670.         if (!file_exists(helpfile))
  1671.             buildfilename(helpfile, HELP_FILENAME);
  1672.     }
  1673.     else
  1674.         buildfilename(helpfile, HELP_FILENAME);
  1675. }
  1676.  
  1677. static void usage()
  1678. {
  1679.     char helpfile[MAX_PATH];
  1680.     char *tmphelp = helpfile;
  1681.     extern unsigned char *ext_c_ptr;
  1682.  
  1683.     build_helpfile(helpfile);
  1684.   
  1685.     if (ext_c_ptr)
  1686.     {    /* conversion to external format necessary */
  1687.         tmphelp = tempfile(TMP_TMPDIR);
  1688.         CONVERSION = EXT_CONV;
  1689.         if (copyfiles_by_name(helpfile, tmphelp) < 0)
  1690.             tmphelp = helpfile;
  1691.         CONVERSION = NO_CONV;
  1692.     }
  1693.  
  1694.       /* built-in help if pgp.hlp is not available */
  1695.     if (more_file(tmphelp) < 0)
  1696.         fprintf(pgpout,PSTR("\nUsage summary:\
  1697. \nTo encrypt a plaintext file with recipent's public key, type:\
  1698. \n   pgp -e textfile her_userid                 (produces textfile.pgp)\
  1699. \nTo sign a plaintext file with your secret key:\
  1700. \n   pgp -s textfile [-u your_userid]           (produces textfile.pgp)\
  1701. \nTo sign a plaintext file with your secret key, and then encrypt it\
  1702. \n   with recipent's public key, producing a .pgp file:\
  1703. \n   pgp -es textfile her_userid [-u your_userid]\
  1704. \nTo encrypt with conventional encryption only:\
  1705. \n   pgp -c textfile\
  1706. \nTo decrypt or check a signature for a ciphertext (.pgp) file:\
  1707. \n   pgp ciphertextfile [plaintextfile]\
  1708. \nTo produce output in ASCII for email, add the -a option to other options.\
  1709. \nTo generate your own unique public/secret key pair:  pgp -kg\
  1710. \nFor help on other key management functions, type:   pgp -k\n"));
  1711.     if (ext_c_ptr)
  1712.         rmtemp(tmphelp);
  1713.     exit(BAD_ARG_ERROR);        /* error exit */
  1714. }
  1715.  
  1716.  
  1717. static void key_usage()
  1718. {
  1719.     char helpfile[MAX_PATH];
  1720.  
  1721.     build_helpfile(helpfile);
  1722.     if (file_exists(helpfile))
  1723.     {    fprintf(pgpout,PSTR("\nFor a usage summary, type:  pgp -h\n"));
  1724.         fprintf(pgpout,PSTR("For more detailed help, consult the PGP User's Guide.\n"));
  1725.     }
  1726.     else
  1727.         fprintf(pgpout,PSTR("\nKey management functions:\
  1728. \nTo generate your own unique public/secret key pair:\
  1729. \n   pgp -kg\
  1730. \nTo add a key file's contents to your public or secret key ring:\
  1731. \n   pgp -ka keyfile [keyring]\
  1732. \nTo remove a key or a user ID from your public or secret key ring:\
  1733. \n   pgp -kr userid [keyring]\
  1734. \nTo edit your user ID or pass phrase:\
  1735. \n   pgp -ke your_userid [keyring]\
  1736. \nTo extract (copy) a key from your public or secret key ring:\
  1737. \n   pgp -kx userid keyfile [keyring]\
  1738. \nTo view the contents of your public key ring:\
  1739. \n   pgp -kv[v] [userid] [keyring]\
  1740. \nTo check signatures on your public key ring:\
  1741. \n   pgp -kc [userid] [keyring]\
  1742. \nTo sign someone else's public key on your public key ring:\
  1743. \n   pgp -ks her_userid [-u your_userid] [keyring]\
  1744. \nTo remove selected signatures from a userid on a keyring:\
  1745. \n   pgp -krs userid [keyring]\
  1746. \n"));
  1747.     exit(BAD_ARG_ERROR);        /* error exit */
  1748. }
  1749.